#include "engine.h"
#include "gui.h"
#include "render/rendersystem.h"
#include <gl/glew.h>
#pragma warning (disable:4355)

DEFINE_ENTITY(guitexture_t,entity_t);
PROPERTY_BINDING_BEGIN(guitexture_t)
	BIND_PROPERTY(guitexture_t,top,float);
	BIND_PROPERTY(guitexture_t,left,float);
	BIND_PROPERTY(guitexture_t,width,float);
	BIND_PROPERTY(guitexture_t,height,float);
	BIND_PROPERTY(guitexture_t,depth,float);
	BIND_PROPERTY(guitexture_t,color,color4f);
	BIND_PROPERTY(guitexture_t,uvx,float);
	BIND_PROPERTY(guitexture_t,uvy,float);
	BIND_PROPERTY(guitexture_t,uvwidth,float);
	BIND_PROPERTY(guitexture_t,uvheight,float);
	BIND_PROPERTY_DATA(guitexture_t,texturename,stringhash,&texture_property_data);
	BIND_PROPERTY(guitexture_t,background,bool);
PROPERTY_BINDING_END

void guitexture_renderobject_t::setupbuffers()
{
	gt->setupbuffers();
}

void guitexture_renderobject_t::onrender()
{
	gt->onrender();
}

guitexture_t::guitexture_t():ro(this)
{
	depth=0;
	top=0;
	left=0;
	width=100;
	height=100;
	color.set(1,1,1,1);
	act_hscale=1;
	act_uvx=act_uvy=0;
	uvx=0;
	uvy=0;
	uvwidth=1;
	uvheight=1;
	background=false;
}


void guitexture_t::setverts()
{
	float xs=(float)RSYS->screen_size_horizontal;
	float ys=(float)RSYS->screen_size_vertical;
	float4 p(2*(left-xs/2)/xs,2*(top-ys/2)/ys,(background ? 0.99f : 0.01f), depth);
	p.y=-p.y;
	float3 s(2*width/xs,2*height/ys,0);
	s.x*=act_hscale;
	vert[0].pos=p;
	vert[0].color=act_color;
	vert[0].uv.set(uvx,uvy);

	vert[1]=vert[0];
	vert[1].pos+=float4(s.x,0,0,0);

	vert[2]=vert[1];
	vert[2].pos+=float4(0,-s.y,0,0);

	vert[3]=vert[2];
	vert[3].pos+=float4(-s.x,0,0,0);

	vert[1].uv.set(act_uvx+act_hscale*uvwidth,act_uvy);
	vert[2].uv.set(act_uvx+act_hscale*uvwidth,act_uvy+uvheight);
	vert[3].uv.set(act_uvx,act_uvy+uvheight);
}

void guitexture_t::setcolor(const float4& color)
{
	act_color=color;
	vert[0].color=color;
	vert[1].color=color;
	vert[2].color=color;
	vert[3].color=color;
}

void guitexture_t::setuv(float _x,float _y)
{
	act_uvx=_x;
	act_uvy=_y;
	setverts();
}

void guitexture_t::setscale(float _scaleHoriz,float _scale_Vert)
{
	act_hscale=_scaleHoriz;
	setverts();
//	vert[2].pos.y*=_scale_Vert;
//	vert[3].pos.y*=_scale_Vert;
//	vert[2].uv.y*=_scale_Vert;
//	vert[3].uv.y*=_scale_Vert;
}

void guitexture_t::init()
{
	entity_t::init();
	act_color=color;
	act_uvx=uvx;
	act_uvy=uvy;
	setverts();
}

void guitexture_t::onload()
{
	entity_t::onload();
	material=!background ? RSYS->get_material("guitexture") : RSYS->get_material("guitexture_background");
	vb.init_dynamic(material->vdecl);
	texture=RSYS->get_texture(texturename);

	act_color=color;
	act_uvx=uvx;
	act_uvy=uvy;
	setverts();
}

#ifdef LEO_DESIGNER
void guitexture_t::onchangeproperty(const stringhash& propname)
{
	entity_t::onchangeproperty(propname);
	setverts();

	if (propname=="texturename")
	{
		texture=RSYS->get_texture(texturename);
	}
}
#endif

void guitexture_t::render()
{
	RSYS->render_custom_object(&ro);
}

void guitexture_t::setupbuffers()
{
	guitexture_vertex_t* bv=(guitexture_vertex_t*)vb.lock(4);

	bv[0]=vert[0];
	bv[1]=vert[1];
	bv[2]=vert[2];
	bv[3]=vert[3];
	vb.unlock();

}

void guitexture_t::onrender()
{
	vb.set();
	RSYS->quadib.set();
	if (texture)
	{
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, texture->hwid);
	}
	material->set();
	glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,0);
}


void set_guitexture_color(guitexture_t* t,const float4& c)
{
	ASSERT(t && t->get_typeid()==guitexture_t::get_class_typeid());
	t->setcolor(c);
}

void set_guitexture_scale(guitexture_t* t,float scaleHoriz,float scaleVert)
{
	ASSERT(t && t->get_typeid()==guitexture_t::get_class_typeid());
	t->setscale(scaleHoriz,scaleVert);
}

#include "script/script.h"





static const char* alignstr[]={"align left","align right",NULL};

DEFINE_ENTITY(guitext_t,entity_t);
PROPERTY_BINDING_BEGIN(guitext_t)
	BIND_PROPERTY(guitext_t,posX,float);
	BIND_PROPERTY(guitext_t,posY,float);
	BIND_PROPERTY(guitext_t,depth,float);
	BIND_PROPERTY(guitext_t,size,float);
	BIND_PROPERTY_DATA(guitext_t,align,enum,alignstr);
	BIND_PROPERTY(guitext_t,color,color4f);
	BIND_PROPERTY(guitext_t,text,string);
PROPERTY_BINDING_END

void guitext_renderobject_t::setupbuffers()
{
	gt->setupbuffers();
}

void guitext_renderobject_t::onrender()
{
	gt->onrender();
}

guitext_t::guitext_t():ro(this)
{
	depth=0;
	posX=0;
	posY=0;
	size=1;
	align=0;
	color.set(1,1,1,1);
	text="DEFAULT TEXT";
}

#include "font/font.h"

void guitext_t::setverts()
{
	const char* text_=act_text.c_str();
	font_t* font_=get_font("textures/fonts/palatino");
	float string_width=0;
	const float texture_width=font_->texture_width;
	const float screenx=(float)RSYS->screen_size_horizontal;
	const float screeny=(float)RSYS->screen_size_vertical;
	const float ratex=act_size*2.0f/screenx*texture_width;
	const float ratey=act_size*2.0f/screeny*texture_width;

	if (align!=0)
	{

		string_width=0;

		while (*text_)
		{
			int index=(unsigned char)*text_-font_->start_index;
			const float4& luv=font_->buv[index];
			const float realw=luv.z*ratex;
			string_width+=realw;
			++text_;
		}
		string_width*=screenx/2;
		if (align==2)
		{
			string_width/=2;
			string_width=floorf(string_width);
			string_width*=2;
		}
		else
			string_width=floorf(string_width+0.49f);
	}

	vert.resize(act_text.size()*4);




	guitext_vertex_t* ptr=&vert[0];
	float x=(act_pos.x-string_width)*2.0f/screenx-1;
	float y=1.0f-act_pos.y*2.0f/screeny;
	for (unsigned charindex=0; charindex<act_text.size(); ++charindex,ptr+=4)
	{
		char ch=act_text[charindex];
		const int index=ch-font_->start_index;
		const float4& luv=font_->buv[index];
		const float xadd=luv.z*ratex;
		const float yadd=luv.w*ratey;

		ptr[0].pos.x=x;
		ptr[0].pos.y=y;
		ptr[0].pos.z=act_depth;
		ptr[1].pos.x=x+xadd;
		ptr[1].pos.y=y;
		ptr[1].pos.z=act_depth;
		ptr[2].pos.x=x+xadd;
		ptr[2].pos.y=y-yadd;
		ptr[2].pos.z=act_depth;
		ptr[3].pos.x=x;
		ptr[3].pos.y=y-yadd;
		ptr[3].pos.z=act_depth;

		x+=xadd;

		ptr[0].uv.set(luv.x, luv.y);
		ptr[1].uv.set(luv.x+luv.z, luv.y);
		ptr[2].uv.set(luv.x+luv.z, luv.y+luv.w);
		ptr[3].uv.set(luv.x, luv.y+luv.w);


		ptr[0].color=act_color;
		ptr[1].color=act_color;
		ptr[2].color=act_color;
		ptr[3].color=act_color;

	}
}

void guitext_t::onload()
{
	entity_t::onload();
	rendermaterial_t* material=RSYS->get_material("font");
	vb.init_dynamic(material->vdecl);

	act_pos.set(posX,posY);
	act_depth=depth;
	act_size=size;
	act_color=color;
	act_text=text;
	act_size=size;
	setverts();
}

void guitext_t::init()
{
	act_pos.set(posX,posY);
	act_depth=depth;
	act_size=size;
	act_color=color;
	act_size=size;
	act_text=text;
	setverts();
	entity_t::init();
}

void guitext_t::render()
{
	entity_t::render();
	RSYS->render_custom_object(&ro);

}

void guitext_t::setupbuffers()
{
	if (!vert.size())
		return;
	guitext_vertex_t* bv=(guitext_vertex_t*)vb.lock(vert.size());

	memcpy(bv,&vert[0],vert.size()*sizeof(guitext_vertex_t));
	vb.unlock();

}

void guitext_t::onrender()
{
	if (!vert.size())
		return;
	vb.set();
	RSYS->quadib.set();
//	font_t* font=get_font("textures/fonts/palatino");
	rendertexture_t* texture=RSYS->get_texture("textures/fonts/palatino");
	if (texture)
	{
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, texture->hwid);
	}
	rendermaterial_t* material=RSYS->get_material("font");
	material->set();
	glDrawElements(GL_TRIANGLES,6*act_text.size(),GL_UNSIGNED_SHORT,0);
}

#ifdef LEO_DESIGNER
void guitext_t::onchangeproperty(const stringhash& propname)
{
	entity_t::onchangeproperty(propname);

	if (propname=="text")
	{
		act_text=text;
	}
	else if (propname=="depth")
	{
		act_depth=depth;
	}
	else if (propname=="posX")
	{
		act_pos.x=posX;
	}
	else if (propname=="posY")
	{
		act_pos.y=posY;
	}
	else if (propname=="size")
	{
		act_size=size;
	}
	else if (propname=="color")
	{
		act_color=color;
	}
	setverts();
}
#endif

void guitext_t::setcolor(const float4& _color)
{
	act_color=_color;
	setverts();
}
void guitext_t::setdepth(float _depth)
{
	act_depth=_depth;
	setverts();
}

void guitext_t::setpos(float2 _pos)
{
	act_pos=_pos;
	setverts();
}
void guitext_t::settext(const string& _text)
{
	act_text=_text;
	setverts();
}

void set_guitext_color(guitext_t* e, const float4& _color)
{
	ASSERT(e && e->isa(guitext_t::get_class_typeid()));
	e->setcolor(_color);
}

void set_guitext_depth(guitext_t* e, float _depth)
{
	ASSERT(e && e->isa(guitext_t::get_class_typeid()));
	e->setdepth(_depth);
}

void set_guitext_pos(guitext_t* e, float xpos,float ypos)
{
	ASSERT(e && e->isa(guitext_t::get_class_typeid()));
	e->setpos(float2(xpos,ypos));
}

void set_guitext_text(guitext_t* e, const string& _text)
{
	ASSERT(e && e->isa(guitext_t::get_class_typeid()));
	e->settext(_text);
}


script_fn_registering_begin(gui)
register_script_fn("void set_guitexture_color(int,const float4& in)",set_guitexture_color);
register_script_fn("void set_guitexture_scale(int,float,float)",set_guitexture_scale);

register_script_fn("void set_guitext_text(int,const string& in)",set_guitext_text);
register_script_fn("void set_guitext_color(int,const float4& in)",set_guitext_color);
register_script_fn("void set_guitext_depth(int,float)",set_guitext_depth);
register_script_fn("void set_guitext_pos(int,float,float)",set_guitext_pos);
script_fn_registering_end
